package com.appspot.yttv.client.model;


import com.appspot.yttv.client.PlaylistProvider;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * A station, showing videos on a certain topic.
 * 
 * From the client's point of view, a station essentially is nothing but a
 * continuous stream of videos associated with a name.
 * 
 * @author Martin Landers
 */
public class Station {
	
	/** The name of the station. */
	private String name;
	
	/** Provides the station with playlists. */
	private PlaylistProvider playlistProvider;

	/** The station's current playlist. */
	private Playlist playlist;
	
	/** The next video to return (index into the playlist). */
	private int nextVideo = -1;
	
	/**
	 * Creates a new station.
	 * 
	 * @param name The station's name.
	 * @param provider Provider the station gets playlists from.
	 */
	public Station(String name, PlaylistProvider provider) {
		this.name = name;
		this.playlistProvider = provider;
		doRefresh();
	}

	/**
	 * @return The station's name.
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * Asynchronously refreshes the station's playlist and resets state.
	 */
	public void refresh() {
		doRefresh();
	}

	/**
	 * Asynchronously refreshes the station's playlist and resets state.
	 */
	private void doRefresh() {
		playlistProvider.getPlaylist(new AsyncCallback<Playlist>() {
			public void onFailure(Throwable caught) {
				// Unable to get new playlist. Let's just start over for now.
				resetPlaylist(Station.this.playlist);
			}

			public void onSuccess(Playlist result) {
				resetPlaylist(result);
			}
		});
	}
	
	/**
	 * Resets the playlist.
	 * 
	 * @param list The new playlist.
	 */
	private void resetPlaylist(Playlist list) {
		this.playlist = list;
		this.nextVideo = 0;
	}
	
	/**
	 * Gets the next video from the station's playlist.
	 * 
	 * @return The next video or <code>null</code> if there are no videos yet.
	 */
	public Video nextVideo() {
		if (this.nextVideo == -1 || this.playlist == null) {
			return null;
		}
		
		Video v = this.playlist.get(nextVideo);

		if (goToNext()) {
			refresh();
		}
		
		return v;
	}
	
	/**
	 * Updates nextVideo to point to the next video.
	 * 
	 * @return <code>true</code> if we've wrapped over.
	 */
	private boolean goToNext() {
		nextVideo++;
		nextVideo %= this.playlist.size();
		return nextVideo == 0;
	}
	
}
